package com.wang.jmonkey.modules.system.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wang.jmonkey.common.exception.ServiceException;
import com.wang.jmonkey.common.utils.TreeUtil;
import com.wang.jmonkey.modules.system.mapper.SystemAreaMapper;
import com.wang.jmonkey.modules.system.model.dto.SystemAreaTreeDto;
import com.wang.jmonkey.modules.system.model.entity.SystemAreaEntity;
import com.wang.jmonkey.modules.system.service.SystemAreaService;
import com.wang.jmonkey.redis.utils.LockUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.List;

/**
 * 区域信息(SystemArea)表服务实现类
 *
 * @author HeJiawang
 * @since 2021-05-14 16:12:58
 */
@Service
public class SystemAreaServiceImpl extends ServiceImpl<SystemAreaMapper, SystemAreaEntity> implements SystemAreaService {

    /**
     * mapper
     */
    @Autowired
    private SystemAreaMapper mapper;

    /**
     * 事务锁key <br/>
     * 在新增或修改信息时，要维护path字段，所以要锁资源
     */
    private static final String LOCK_KEY = "SYSTEM_AREA_LOCK_KEY";

    /**
     * 维护path字段信息
     * @param entity 区域信息
     */
    private void buildAreaPath (SystemAreaEntity entity) {
        String path = StrUtil.EMPTY;

        if (ObjectUtil.isNotEmpty(entity.getParentId())) {
            SystemAreaEntity parentArea = mapper.selectById(entity.getParentId());
            if (ObjectUtil.isEmpty(parentArea)) throw new ServiceException("上级区域信息已不存在");

            // 维护path字段
            path = String.format(
                    "%s%s,",
                    StrUtil.isEmpty(parentArea.getPath()) ? StrUtil.EMPTY : parentArea.getPath(),
                    parentArea.getId()
            );
        }

        entity.setPath(path);
    }

    /**
     * 新增区域信息
     * @param entity 区域信息
     * @return boolean
     */
    @Override
    public boolean save(SystemAreaEntity entity) {
        try {
            LockUtil.lock(LOCK_KEY);

            // 维护path字段值
            buildAreaPath(entity);

            return super.save(entity);
        } finally {

            if (LockUtil.isLocked(LOCK_KEY)) {
                LockUtil.unlock(LOCK_KEY);
            }
        }
    }

    /**
     * 修改区域信息
     * @param entity 区域id
     * @return boolean
     */
    @Transactional
    @Override
    public boolean updateById(SystemAreaEntity entity) {
        try {
            LockUtil.lock(LOCK_KEY);

            SystemAreaEntity area = mapper.selectById(entity.getId());
            if (ObjectUtil.isEmpty(area)) throw new ServiceException("区域信息不存在");

            // 维护path字段值
            buildAreaPath(entity);

            // 更新下级区域信息path字段值
            String oldPath = String.format(
                    "%s%s,",
                    StrUtil.isEmpty(area.getPath()) ? StrUtil.EMPTY : area.getPath(),
                    area.getId()
            );
            String newPath = String.format(
                    "%s%s,",
                    StrUtil.isEmpty(entity.getPath()) ? StrUtil.EMPTY : entity.getPath(),
                    entity.getId()
            );

            return super.updateById(entity) && mapper.refreshPath(oldPath, newPath) >= 0;
        } finally {

            if (LockUtil.isLocked(LOCK_KEY)) {
                LockUtil.unlock(LOCK_KEY);
            }
        }
    }

    /**
     * 删除区域信息
     * @param id 区域信息id
     * @return true 删除成功
     */
    @Transactional
    @Override
    public boolean removeById(Serializable id) {
        try {
            LockUtil.lock(LOCK_KEY);

            SystemAreaEntity area = mapper.selectById(id);
            if (ObjectUtil.isEmpty(area)) return false;

            // 根据path删除下级区域
            String path = String.format(
                    "%s%s,",
                    StrUtil.isEmpty(area.getPath()) ? StrUtil.EMPTY : area.getPath(),
                    area.getId()
            );
            QueryWrapper<SystemAreaEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.likeRight("path", path);

            super.remove(queryWrapper);
            return super.removeById(id);
        } finally {

            if (LockUtil.isLocked(LOCK_KEY)) {
                LockUtil.unlock(LOCK_KEY);
            }
        }
    }

    /**
     * 获取树形结构数据
     * @return 树形结构数据集合
     */
    @Override
    public List<SystemAreaTreeDto> listTree() {
        List<SystemAreaTreeDto> treeDtoList = mapper.listTree();
        return TreeUtil.build(treeDtoList);
    }
}
